//
//  CCClippingSkeletalSprite.cpp
//  BattleEmpireTest
//
//  Created by droidhang on 13-7-2.
//
//

#include "CCClippingSkeletalSprite.h"
#include "CCSkeletonCache.h"

CCClippingSkeletalSprite::CCClippingSkeletalSprite() {
    _sprtAntialias=NULL;
}

CCClippingSkeletalSprite::~CCClippingSkeletalSprite() {
    _bvt.clear();
}

CCClippingSkeletalSprite* CCClippingSkeletalSprite::create(const char* key,ClippingNode* clipper,const vector<bool>& bvt,Sprite* sprtAntialias) {
    CCSkeleton* s=CCSkeletonCache::getInstance()->getSkeleton(key);
	return create(s,clipper,bvt,sprtAntialias);
}

CCClippingSkeletalSprite* CCClippingSkeletalSprite::create(CCSkeleton* s,ClippingNode* clipper,const vector<bool>& bvt,Sprite* sprtAntialias) {
    CCClippingSkeletalSprite* sprite = new CCClippingSkeletalSprite();
    if (sprite && sprite->init(clipper, bvt,sprtAntialias)) {
        sprite->setSkeleton(s);
        return (CCClippingSkeletalSprite*)sprite->autorelease();
    }
	CC_SAFE_DELETE(sprite);
    return NULL;
}

bool CCClippingSkeletalSprite::init(cocos2d::ClippingNode *clipper, const vector<bool> &bvt,Sprite* sprtAntialias) {
    
    if (!CCSkeletalSprite::init()) {
        return false;
    }
    
    _bvt=bvt;
    _iter=_bvt.begin();
    
    clipper->retain();
    
    Node* sten=clipper->getStencil();
    sten->setScaleX(1.0/getScaleX()*sten->getScaleX());
    sten->setScaleY(1.0/getScaleY()*sten->getScaleY());
    
    _rootSpriteList.push_back(clipper);
    
    if (sprtAntialias) {
        sprtAntialias->retain();
        _sprtAntialias=sprtAntialias;
        _sprtAntialias->setPosition(sten->getPosition());
        _sprtAntialias->setAnchorPoint(sten->getAnchorPoint());
        _sprtAntialias->setScaleX(sten->getScaleX());
        _sprtAntialias->setScaleY(sten->getScaleY());
    }
    
    return true;
}

void CCClippingSkeletalSprite::createSprites(cocos2d::Sprite *sprite,bool &lastAdditive,bool &nowAdditive) {
    if (_iter==_bvt.end() || *_iter==true) {
        //need clipping
        (*_rootSpriteList.begin())->addChild(sprite);
    }
    else {
        
        SpriteBatchNode* rootSprite=NULL;
        if (_rootSpriteList.size()==1) {
            rootSprite=SpriteBatchNode::createWithTexture(sprite->getTexture());
            _rootSpriteList.push_back(rootSprite);
            rootSprite->retain();
            lastAdditive=nowAdditive;
            if (nowAdditive) {
                BlendFunc blendFunc;
                blendFunc.src=GL_SRC_ALPHA;
                blendFunc.dst=GL_ONE;
                rootSprite->setBlendFunc(blendFunc);
            }
        }
        else {
            rootSprite=(SpriteBatchNode*)*_rootSpriteList.rbegin();
            if (rootSprite->getTexture()->getName()!=sprite->getTexture()->getName() || lastAdditive!=nowAdditive) {
                rootSprite=SpriteBatchNode::createWithTexture(sprite->getTexture());
                _rootSpriteList.push_back(rootSprite);
                rootSprite->retain();
                if (nowAdditive) {
                    BlendFunc blendFunc;
                    blendFunc.src=GL_SRC_ALPHA;
                    blendFunc.dst=GL_ONE;
                    rootSprite->setBlendFunc(blendFunc);
                }
                lastAdditive=nowAdditive;
            }
        }
        rootSprite->addChild(sprite);
        //sprite->retain();
        //_rootSpriteList.push_back(sprite);
    }
    _iter++;
}

void CCClippingSkeletalSprite::visit() {
    // quick return if not visible. children won't be drawn.
    
    if (!_visible)
    {
        return;
    }
    
    auto it=_rootSpriteList.begin();
    
    (*it)->setPosition(getPosition());
    (*it)->setRotation(getRotation());
    (*it)->setScaleX(getScaleX());
    (*it)->setScaleY(getScaleY());
    (*it)->visit();
    
    kmGLPushMatrix();
    
    if (_grid && _grid->isActive())
    {
        _grid->beforeDraw();
    }
    
    this->transform();
    
    if (_sprtAntialias) {
        _sprtAntialias->visit();
    }
    
    for (it++ ; it!=_rootSpriteList.end(); it++) {
        (*it)->visit();
    }
    
    // reset for next frame
    _orderOfArrival = 0;
    
    if (_grid && _grid->isActive())
    {
        _grid->afterDraw(this);
    }
    
    kmGLPopMatrix();
}

void CCClippingSkeletalSprite::setShaderProgram(cocos2d::GLProgram *pShaderProgram) {
    auto it = _rootSpriteList.begin();
    Object* object;
    CCARRAY_FOREACH((*it)->getChildren(),object ) {
        Node* node=(Node*)object;
        node->setShaderProgram(pShaderProgram);
    }

    for (it++ ; it!=_rootSpriteList.end(); it++) {
        (*it)->setShaderProgram(pShaderProgram);
    }
}